"""
LAN对讲机 - 专业安装向导
使用目录版（包含所有依赖），确保用户安装后可直接运行
"""
import os
import sys
import shutil
import winreg
import json
from pathlib import Path
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import threading


class InstallerWizard:
    """安装向导主类"""
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("LAN对讲机 安装向导")
        self.root.geometry("650x580")  # 增大窗口尺寸
        self.root.resizable(False, False)
        
        # 居中显示
        self.center_window()
        
        # 安装配置
        self.app_name = "LAN对讲机"
        self.app_version = "2.1.0"
        self.publisher = "WalkieTalkie Team"
        
        # 默认安装路径
        self.install_path = str(Path.home() / "AppData" / "Local" / self.app_name)
        
        # 安装选项
        self.create_desktop_shortcut = tk.BooleanVar(value=True)
        self.create_startmenu_shortcut = tk.BooleanVar(value=True)
        self.enable_autostart = tk.BooleanVar(value=False)
        
        # 当前页面
        self.current_page = 0
        self.pages = []
        
        # 安装源路径（包含所有文件的目录）
        self.source_dir = self.get_source_directory()
        
        # 创建UI
        self.setup_ui()
        
    def center_window(self):
        """窗口居中"""
        self.root.update_idletasks()
        width = 650
        height = 580
        x = (self.root.winfo_screenwidth() // 2) - (width // 2)
        y = (self.root.winfo_screenheight() // 2) - (height // 2)
        self.root.geometry(f"{width}x{height}+{x}+{y}")
    
    def get_source_directory(self):
        """获取安装源目录（包含所有要安装的文件）"""
        if getattr(sys, 'frozen', False):
            # 打包后的exe，从临时目录或同级目录查找
            base_dir = os.path.dirname(sys.executable)
            
            # 方案1：查找同级的 "app_files" 目录
            app_files = os.path.join(base_dir, "app_files")
            if os.path.exists(app_files):
                return app_files
            
            # 方案2：查找 _MEIPASS 临时目录
            if hasattr(sys, '_MEIPASS'):
                meipass = os.path.join(sys._MEIPASS, "app_files")
                if os.path.exists(meipass):
                    return meipass
            
            # 方案3：返回基础目录
            return base_dir
        else:
            # 开发环境，从dist目录获取
            dev_source = os.path.join(os.path.dirname(__file__), "dist", "LAN对讲机")
            if os.path.exists(dev_source):
                return dev_source
            return os.path.dirname(__file__)
    
    def setup_ui(self):
        """设置UI"""
        # 标题栏
        title_frame = tk.Frame(self.root, bg="#2196F3", height=80)
        title_frame.pack(fill=tk.X)
        title_frame.pack_propagate(False)
        
        title_label = tk.Label(
            title_frame,
            text=f"{self.app_name} {self.app_version}\n安装向导",
            font=("微软雅黑", 16, "bold"),
            bg="#2196F3",
            fg="white"
        )
        title_label.pack(expand=True)
        
        # 内容区域 - 使用固定高度，避免挤压按钮
        self.content_frame = tk.Frame(self.root, height=390)
        self.content_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        self.content_frame.pack_propagate(False)  # 防止内容撑大
        
        # 创建所有页面
        self.create_pages()
        
        # 底部按钮栏 - 固定高度，确保始终可见
        button_frame = tk.Frame(self.root, bg="#e8e8e8", height=70)
        button_frame.pack(fill=tk.X, side=tk.BOTTOM)
        button_frame.pack_propagate(False)  # 防止内容影响高度
        
        # 按钮容器（居中）
        btn_container = tk.Frame(button_frame, bg="#e8e8e8")
        btn_container.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
        
        self.back_btn = tk.Button(
            btn_container,
            text="< 上一步",
            command=self.prev_page,
            font=("微软雅黑", 10),
            width=12,
            height=2,
            state=tk.DISABLED
        )
        self.back_btn.pack(side=tk.LEFT, padx=8)
        
        self.next_btn = tk.Button(
            btn_container,
            text="下一步 >",
            command=self.next_page,
            font=("微软雅黑", 10, "bold"),
            width=12,
            height=2,
            relief=tk.RAISED,
            borderwidth=2
        )
        self.next_btn.pack(side=tk.LEFT, padx=8)
        
        self.cancel_btn = tk.Button(
            btn_container,
            text="取消",
            command=self.cancel_install,
            font=("微软雅黑", 10),
            width=12,
            height=2
        )
        self.cancel_btn.pack(side=tk.LEFT, padx=8)
        
        # 显示第一页
        self.show_page(0)
    
    def create_pages(self):
        """创建所有向导页面"""
        # 页面1：欢迎页面
        self.pages.append(self.create_welcome_page())
        
        # 页面2：许可协议
        self.pages.append(self.create_license_page())
        
        # 页面3：安装选项
        self.pages.append(self.create_options_page())
        
        # 页面4：安装进度
        self.pages.append(self.create_progress_page())
        
        # 页面5：完成页面
        self.pages.append(self.create_finish_page())
    
    def create_welcome_page(self):
        """欢迎页面"""
        frame = tk.Frame(self.content_frame)
        
        welcome_text = f"""
欢迎使用 {self.app_name} 安装向导！

本向导将引导您完成 {self.app_name} 的安装。

这是一个局域网语音对讲工具，让您可以通过局域网
与同事、朋友进行实时语音通话。

主要特性：
  • 简单易用的界面
  • 低延迟的语音传输
  • 支持多人语音对讲
  • 按键对讲（PTT）模式
  • 系统托盘驻留

点击"下一步"继续安装。
        """
        
        text_widget = tk.Text(
            frame,
            wrap=tk.WORD,
            font=("微软雅黑", 10),
            relief=tk.FLAT,
            bg=self.root.cget('bg'),
            height=16,
            width=60
        )
        text_widget.insert("1.0", welcome_text)
        text_widget.config(state=tk.DISABLED)
        text_widget.pack(fill=tk.BOTH, expand=True, pady=10)
        
        return frame
    
    def create_license_page(self):
        """许可协议页面"""
        frame = tk.Frame(self.content_frame)
        
        label = tk.Label(
            frame,
            text="请阅读以下许可协议",
            font=("微软雅黑", 11, "bold")
        )
        label.pack(pady=(0, 10))
        
        # 许可协议文本
        license_text = """
MIT License

Copyright (c) 2024 LAN对讲机

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

使用说明：
1. 本软件仅供个人和内部使用
2. 请勿用于非法用途
3. 软件按"原样"提供，不提供任何保证
        """
        
        text_frame = tk.Frame(frame)
        text_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        scrollbar = tk.Scrollbar(text_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        text_widget = tk.Text(
            text_frame,
            wrap=tk.WORD,
            font=("Consolas", 8),
            yscrollcommand=scrollbar.set,
            height=15
        )
        text_widget.insert("1.0", license_text)
        text_widget.config(state=tk.DISABLED)
        text_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        scrollbar.config(command=text_widget.yview)
        
        # 接受协议复选框
        self.accept_license = tk.BooleanVar(value=False)
        accept_check = tk.Checkbutton(
            frame,
            text="我接受许可协议的条款",
            variable=self.accept_license,
            font=("微软雅黑", 10),
            command=self.update_buttons
        )
        accept_check.pack(pady=10)
        
        return frame
    
    def create_options_page(self):
        """安装选项页面"""
        frame = tk.Frame(self.content_frame)
        
        # 安装路径
        path_label = tk.Label(
            frame,
            text="选择安装位置",
            font=("微软雅黑", 11, "bold")
        )
        path_label.pack(anchor=tk.W, pady=(0, 5))
        
        path_frame = tk.Frame(frame)
        path_frame.pack(fill=tk.X, pady=(0, 20))
        
        self.path_entry = tk.Entry(
            path_frame,
            font=("微软雅黑", 9),
            width=50
        )
        self.path_entry.insert(0, self.install_path)
        self.path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
        
        browse_btn = tk.Button(
            path_frame,
            text="浏览...",
            command=self.browse_install_path,
            font=("微软雅黑", 9)
        )
        browse_btn.pack(side=tk.LEFT, padx=(5, 0))
        
        # 空间提示
        space_label = tk.Label(
            frame,
            text="需要磁盘空间：约 150 MB",
            font=("微软雅黑", 8),
            fg="gray"
        )
        space_label.pack(anchor=tk.W, pady=(0, 15))
        
        # 安装选项
        options_label = tk.Label(
            frame,
            text="安装选项",
            font=("微软雅黑", 11, "bold")
        )
        options_label.pack(anchor=tk.W, pady=(0, 10))
        
        desktop_check = tk.Checkbutton(
            frame,
            text="创建桌面快捷方式",
            variable=self.create_desktop_shortcut,
            font=("微软雅黑", 10)
        )
        desktop_check.pack(anchor=tk.W, pady=2)
        
        startmenu_check = tk.Checkbutton(
            frame,
            text="创建开始菜单快捷方式",
            variable=self.create_startmenu_shortcut,
            font=("微软雅黑", 10)
        )
        startmenu_check.pack(anchor=tk.W, pady=2)
        
        autostart_check = tk.Checkbutton(
            frame,
            text="开机自动启动",
            variable=self.enable_autostart,
            font=("微软雅黑", 10)
        )
        autostart_check.pack(anchor=tk.W, pady=2)
        
        return frame
    
    def create_progress_page(self):
        """安装进度页面"""
        frame = tk.Frame(self.content_frame)
        
        self.progress_label = tk.Label(
            frame,
            text="准备安装...",
            font=("微软雅黑", 11)
        )
        self.progress_label.pack(pady=(50, 20))
        
        self.progress_bar = ttk.Progressbar(
            frame,
            mode='indeterminate',
            length=400
        )
        self.progress_bar.pack(pady=20)
        
        self.progress_detail = tk.Label(
            frame,
            text="",
            font=("微软雅黑", 9),
            fg="gray"
        )
        self.progress_detail.pack(pady=10)
        
        return frame
    
    def create_finish_page(self):
        """完成页面"""
        frame = tk.Frame(self.content_frame)
        
        self.finish_title = tk.Label(
            frame,
            text="",
            font=("微软雅黑", 14, "bold"),
            fg="green"
        )
        self.finish_title.pack(pady=(50, 20))
        
        self.finish_message = tk.Text(
            frame,
            wrap=tk.WORD,
            font=("微软雅黑", 10),
            relief=tk.FLAT,
            bg=self.root.cget('bg'),
            height=8
        )
        self.finish_message.pack(fill=tk.BOTH, expand=True, pady=20)
        
        self.launch_app = tk.BooleanVar(value=True)
        self.launch_check = tk.Checkbutton(
            frame,
            text=f"立即启动 {self.app_name}",
            variable=self.launch_app,
            font=("微软雅黑", 10)
        )
        self.launch_check.pack(pady=10)
        
        return frame
    
    def show_page(self, page_index):
        """显示指定页面"""
        # 隐藏所有页面
        for page in self.pages:
            page.pack_forget()
        
        # 显示当前页面
        if 0 <= page_index < len(self.pages):
            self.pages[page_index].pack(fill=tk.BOTH, expand=True)
            self.current_page = page_index
            self.update_buttons()
    
    def update_buttons(self):
        """更新按钮状态"""
        # 上一步按钮
        if self.current_page == 0:
            self.back_btn.config(state=tk.DISABLED)
        else:
            self.back_btn.config(state=tk.NORMAL)
        
        # 下一步/安装/完成按钮
        if self.current_page == len(self.pages) - 2:  # 安装选项页
            self.next_btn.config(text="开始安装", state=tk.NORMAL)
        elif self.current_page == len(self.pages) - 1:  # 完成页
            self.next_btn.config(text="完成", state=tk.NORMAL)
            self.cancel_btn.config(state=tk.DISABLED)
        elif self.current_page == 1:  # 许可协议页
            if self.accept_license.get():
                self.next_btn.config(text="下一步 >", state=tk.NORMAL)
            else:
                self.next_btn.config(state=tk.DISABLED)
        elif self.current_page == len(self.pages) - 2:  # 进度页（安装中）
            self.next_btn.config(state=tk.DISABLED)
            self.back_btn.config(state=tk.DISABLED)
            self.cancel_btn.config(state=tk.DISABLED)
        else:
            self.next_btn.config(text="下一步 >", state=tk.NORMAL)
    
    def next_page(self):
        """下一页"""
        if self.current_page == len(self.pages) - 2:  # 从选项页到进度页（开始安装）
            self.start_installation()
        elif self.current_page == len(self.pages) - 1:  # 完成页
            self.finish_installation()
        else:
            self.show_page(self.current_page + 1)
    
    def prev_page(self):
        """上一页"""
        if self.current_page > 0:
            self.show_page(self.current_page - 1)
    
    def browse_install_path(self):
        """浏览安装路径"""
        path = filedialog.askdirectory(initialdir=os.path.dirname(self.install_path))
        if path:
            self.install_path = os.path.join(path, self.app_name)
            self.path_entry.delete(0, tk.END)
            self.path_entry.insert(0, self.install_path)
    
    def cancel_install(self):
        """取消安装"""
        if messagebox.askyesno("确认", "确定要取消安装吗？"):
            self.root.destroy()
            sys.exit(0)
    
    def start_installation(self):
        """开始安装"""
        # 获取安装路径
        self.install_path = self.path_entry.get()
        
        # 显示进度页
        self.show_page(self.current_page + 1)
        self.progress_bar.start()
        
        # 在新线程中执行安装
        install_thread = threading.Thread(target=self.perform_installation, daemon=True)
        install_thread.start()
    
    def perform_installation(self):
        """执行安装（在独立线程中）"""
        try:
            success = True
            error_msg = ""
            
            # 1. 检查源目录
            self.update_progress("检查安装文件...", "")
            if not os.path.exists(self.source_dir):
                raise Exception(f"找不到安装源目录：{self.source_dir}")
            
            # 2. 创建安装目录
            self.update_progress("创建安装目录...", self.install_path)
            os.makedirs(self.install_path, exist_ok=True)
            
            # 3. 复制所有文件
            self.update_progress("复制程序文件...", "这可能需要几分钟")
            self.copy_files(self.source_dir, self.install_path)
            
            # 4. 创建快捷方式
            exe_path = os.path.join(self.install_path, f"{self.app_name}.exe")
            
            if self.create_desktop_shortcut.get():
                self.update_progress("创建桌面快捷方式...", "")
                self.create_shortcut(exe_path, "Desktop")
            
            if self.create_startmenu_shortcut.get():
                self.update_progress("创建开始菜单快捷方式...", "")
                self.create_shortcut(exe_path, "StartMenu")
            
            # 5. 设置开机自启动
            if self.enable_autostart.get():
                self.update_progress("配置开机自启动...", "")
                self.set_autostart(exe_path)
            
            # 6. 验证卸载程序
            self.update_progress("验证卸载程序...", "")
            if not self.verify_uninstaller():
                raise Exception("卸载程序不存在")
            
            # 7. 写入注册表
            self.update_progress("写入系统注册表...", "")
            self.write_registry(exe_path)
            
            # 8. 保存安装信息
            self.update_progress("保存安装信息...", "")
            self.save_install_info()
            
        except Exception as e:
            success = False
            error_msg = str(e)
        
        # 停止进度条并显示结果
        self.root.after(0, lambda: self.installation_complete(success, error_msg))
    
    def copy_files(self, src, dst):
        """复制文件和目录"""
        # 使用shutil.copytree但跳过不需要的文件
        ignore_patterns = shutil.ignore_patterns('*.pyc', '__pycache__', '*.log')
        
        # 如果目标已存在，先删除
        if os.path.exists(dst) and os.path.isdir(dst):
            shutil.rmtree(dst)
        
        shutil.copytree(src, dst, ignore=ignore_patterns)
    
    def create_shortcut(self, target_path, location):
        """创建快捷方式"""
        try:
            import win32com.client
            
            shell = win32com.client.Dispatch("WScript.Shell")
            
            if location == "Desktop":
                shortcut_path = os.path.join(
                    os.path.expanduser("~"),
                    "Desktop",
                    f"{self.app_name}.lnk"
                )
            else:  # StartMenu
                start_menu = os.path.join(
                    os.environ["APPDATA"],
                    "Microsoft\\Windows\\Start Menu\\Programs"
                )
                shortcut_path = os.path.join(start_menu, f"{self.app_name}.lnk")
            
            shortcut = shell.CreateShortCut(shortcut_path)
            shortcut.TargetPath = target_path  # 修复：Targetpath -> TargetPath
            shortcut.WorkingDirectory = os.path.dirname(target_path)
            
            # 设置图标
            icon_path = os.path.join(os.path.dirname(target_path), "icon.ico")
            if os.path.exists(icon_path):
                shortcut.IconLocation = icon_path
            
            shortcut.save()
            print(f"快捷方式已创建: {shortcut_path}")
        except ImportError:
            print(f"创建快捷方式失败: 缺少 pywin32 库")
            print("请运行: pip install pywin32")
        except Exception as e:
            print(f"创建快捷方式失败: {e}")
            import traceback
            traceback.print_exc()
    
    def set_autostart(self, exe_path):
        """设置开机自启动"""
        try:
            key = winreg.OpenKey(
                winreg.HKEY_CURRENT_USER,
                r"Software\Microsoft\Windows\CurrentVersion\Run",
                0,
                winreg.KEY_SET_VALUE
            )
            winreg.SetValueEx(key, self.app_name, 0, winreg.REG_SZ, f'"{exe_path}"')
            winreg.CloseKey(key)
        except Exception as e:
            print(f"设置自启动失败: {e}")
    
    def verify_uninstaller(self):
        """验证卸载程序是否存在"""
        uninstaller_exe = os.path.join(self.install_path, "Uninstall.exe")
        if not os.path.exists(uninstaller_exe):
            print(f"警告：卸载程序不存在: {uninstaller_exe}")
            return False
        print(f"卸载程序已就位: {uninstaller_exe}")
        return True
    
    def write_registry(self, exe_path):
        """写入注册表（添加/删除程序）"""
        try:
            key = winreg.CreateKey(
                winreg.HKEY_CURRENT_USER,
                f"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{self.app_name}"
            )
            
            # 使用独立的卸载程序 exe
            uninstall_exe = os.path.join(self.install_path, "Uninstall.exe")
            
            winreg.SetValueEx(key, "DisplayName", 0, winreg.REG_SZ, self.app_name)
            winreg.SetValueEx(key, "DisplayVersion", 0, winreg.REG_SZ, self.app_version)
            winreg.SetValueEx(key, "Publisher", 0, winreg.REG_SZ, self.publisher)
            winreg.SetValueEx(key, "InstallLocation", 0, winreg.REG_SZ, self.install_path)
            winreg.SetValueEx(key, "DisplayIcon", 0, winreg.REG_SZ, exe_path)
            winreg.SetValueEx(key, "UninstallString", 0, winreg.REG_SZ, f'"{uninstall_exe}"')
            winreg.SetValueEx(key, "QuietUninstallString", 0, winreg.REG_SZ, f'"{uninstall_exe}" /S')
            winreg.SetValueEx(key, "NoModify", 0, winreg.REG_DWORD, 1)
            winreg.SetValueEx(key, "NoRepair", 0, winreg.REG_DWORD, 1)
            
            winreg.CloseKey(key)
        except Exception as e:
            print(f"写入注册表失败: {e}")
    
    def save_install_info(self):
        """保存安装信息"""
        install_info = {
            "app_name": self.app_name,
            "version": self.app_version,
            "install_path": self.install_path,
            "install_date": str(Path(self.install_path).stat().st_ctime),
            "desktop_shortcut": self.create_desktop_shortcut.get(),
            "startmenu_shortcut": self.create_startmenu_shortcut.get(),
            "autostart": self.enable_autostart.get()
        }
        
        info_file = os.path.join(self.install_path, "install_info.json")
        with open(info_file, 'w', encoding='utf-8') as f:
            json.dump(install_info, f, indent=2, ensure_ascii=False)
    
    def update_progress(self, message, detail):
        """更新进度信息"""
        self.root.after(0, lambda: self.progress_label.config(text=message))
        self.root.after(0, lambda: self.progress_detail.config(text=detail))
    
    def installation_complete(self, success, error_msg=""):
        """安装完成"""
        self.progress_bar.stop()
        
        if success:
            self.finish_title.config(text="✓ 安装成功！", fg="green")
            message = f"""
{self.app_name} 已成功安装到：
{self.install_path}

您可以通过以下方式启动程序：
• 双击桌面快捷方式（如果已创建）
• 从开始菜单启动
• 直接运行安装目录中的程序

感谢您使用 {self.app_name}！
            """
            self.finish_message.delete("1.0", tk.END)
            self.finish_message.insert("1.0", message)
            self.finish_message.config(state=tk.DISABLED)
        else:
            self.finish_title.config(text="✗ 安装失败", fg="red")
            message = f"""
安装过程中出现错误：

{error_msg}

请检查：
• 安装路径是否可写
• 是否有足够的磁盘空间
• 是否被杀毒软件拦截

您可以尝试：
• 以管理员身份运行安装程序
• 更换安装路径
• 临时关闭杀毒软件
            """
            self.finish_message.delete("1.0", tk.END)
            self.finish_message.insert("1.0", message)
            self.finish_message.config(state=tk.DISABLED)
            self.launch_check.config(state=tk.DISABLED)
        
        # 显示完成页
        self.show_page(len(self.pages) - 1)
    
    def finish_installation(self):
        """完成安装"""
        # 如果选择立即启动
        if self.launch_app.get():
            exe_path = os.path.join(self.install_path, f"{self.app_name}.exe")
            if os.path.exists(exe_path):
                try:
                    import subprocess
                    subprocess.Popen([exe_path], cwd=os.path.dirname(exe_path))
                except Exception as e:
                    messagebox.showerror("错误", f"启动程序失败：{e}")
        
        # 关闭安装程序
        self.root.destroy()
        sys.exit(0)
    
    def run(self):
        """运行安装向导"""
        self.root.mainloop()


if __name__ == "__main__":
    # 检查是否是管理员权限
    try:
        import ctypes
        is_admin = ctypes.windll.shell32.IsUserAnAdmin()
    except:
        is_admin = False
    
    if not is_admin:
        # 提示建议以管理员身份运行
        root = tk.Tk()
        root.withdraw()
        result = messagebox.askyesno(
            "权限提示",
            "建议以管理员身份运行安装程序以获得最佳体验。\n\n是否继续普通安装？",
            icon='warning'
        )
        root.destroy()
        if not result:
            sys.exit(0)
    
    app = InstallerWizard()
    app.run()

